package dkbta.ontology.values;

import dkbta.ontology.loading.OntologyException;
import dkbta.util.time.ISODuration;
import dkbta.util.time.InvalidDurationException;

/**
 * A numeric range of long values (represent milliseconds since the epoch). Can be fully open, fully closed or half-open from either side.<br>
 * <br>
 * Asterisk (*) can be used as a wild card in either side. In minimum it is replaced by
 * <tt>0</tt> and in maximum by <tt>Long.MAX_VALUE</tt>.
 * 
 * @author Uri Kanonov
 */
public class DurationValues{
	/**
	 * Denotes whether equality may or may not be used when comparing the lower bound to a
	 * value
	 */
	private final boolean _isMinE;

	/** The lower bound */
	private final long _min;

	/**
	 * Denotes whether equality may or may not be used when comparing the upper bound to a
	 * value
	 */
	private final boolean _isMaxE;

	/** The lower bound */
	private final long _max;

	/**
	 * Constructs a DurationValues object with the given parameters
	 * 
	 * @param minE The lower bound with equality
	 * @param min The lower bound without equality
	 * @param maxE The upper bound with equality
	 * @param max The upper bound without equality
	 * @throws OntologyException
	 */
	public DurationValues(String minE, String min, String maxE, String max)
			throws OntologyException{
		_isMinE = min.isEmpty();
		_isMaxE = max.isEmpty();
		min = (min.isEmpty()) ? minE : min;
		max = (max.isEmpty()) ? maxE : max;

		// Setting the minimum and maximum
		try{
			_min = parseMinValue(min);
			_max = parseMaxValue(max);
		}catch(InvalidDurationException e){
			throw new OntologyException("Illegal min or max value: [" + min + ", " + max
					+ "]", e);
		}
		if (_min > _max){
			throw new OntologyException("Illegal min or max value: [" + min + ", " + max
					+ "]: min cannot be bigger than max");
		}
	}

	/**
	 * Returns the value of a number (represented by the string min)in the role of a lower
	 * bound
	 * 
	 * @param min The value of a number
	 * @return The value of a number (represented by the string min)in the role of a lower
	 *         bound
	 * @throws InvalidDurationException If min doesn't represent a valid ISO 8601 format
	 *         duration
	 */
	private long parseMinValue(String min) throws InvalidDurationException{
		if ("*".equals(min)){
			return 0;
		}
		return new ISODuration(min).toMillis();
	}

	/**
	 * Returns the value of a number (represented by the string max)in the role of an
	 * upper bound
	 * 
	 * @param max The value of a number
	 * @return The value of a number (represented by the string max)in the role of an
	 *         upper bound
	 * @throws InvalidDurationException If max doesn't represent a valid ISO 8601 format
	 *         duration
	 */
	private long parseMaxValue(String max) throws InvalidDurationException{
		if ("*".equals(max)){
			return Long.MAX_VALUE;
		}
		return new ISODuration(max).toMillis();
	}

	@Override
	public String toString(){
		return (_isMinE ? "[" : "(") + _min + ", "
				+ ((_max == Long.MAX_VALUE) ? "*" : _max) + (_isMaxE ? "]" : ")");

	}

	/**
	 * Checks whether the given duration is in the range specified by min, max, isMinE and
	 * isMaxE
	 * 
	 * @param duration The value
	 * @return Whether the given duration is in the range specified by min, max, isMinE
	 *         and isMaxE
	 */
	public boolean isValid(long duration){
		return ((_isMinE) ? duration >= _min : duration > _min)
				&& ((_isMaxE) ? duration <= _max : duration < _max);
	}
}
